﻿/************************************************************************************************
 * This program is free software; you can redistribute it and/or modify.No terms and conditions!
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * Report bugs or comments to the author:Fred Byamugisha (fredbyk@gmail.com)[Kampala,Uganda]
 ***********************************************************************************************/

/*How to convert a numeric value or currency to English words using C#
 * Url : http://www.codeproject.com/useritems/codesamples.asp
 */

using System;

namespace Jerkymon.Numeric
{


    public class NumberToWord
    {
		#region Static Fields (3)
		private static string[] groupMapping =
            new string[] {
            "Hundred", "Thousand", "Million", "Billion", "Trillion"
        };
		private static string[] onesMapping =
            new string[] {
            "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine",
            "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"
        };
		private static string[] tensMapping =
            new string[] {
            "Twenty", "Thirty", "Fourty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"
        };
		#endregion

		#region Static Methods (6)
		private static string ProcessGroup(int number)
        {
            int tens = number % 100;
            int hundreds = number / 100;

            string retVal = null;
            if (hundreds > 0)
            {
                retVal = onesMapping[hundreds] + " " + groupMapping[0];
            }
            if (tens > 0)
            {
                if (tens < 20)
                {
                    retVal += ((retVal != null) ? " " : "") + onesMapping[tens];
                }
                else
                {
                    int ones = tens % 10;
                    tens = (tens / 10) - 2; // 20's offset

                    retVal += ((retVal != null) ? " " : "") + tensMapping[tens];

                    if (ones > 0)
                    {
                        retVal += ((retVal != null) ? " " : "") + onesMapping[ones];
                    }
                }
            }

            return retVal;
        }

		public static String changeAmountToWords(double numb, string currency)
        {
            return changeToWords(numb.ToString(), true, currency, true);
        }

		private static String changeToWords(String numb, bool isCurrency, String currencySign, bool isCents)
        {
            String val = "", wholeNo = numb, points = "", andStr = "", pointStr = "";
            String signStr = (!string.IsNullOrEmpty(currencySign)) ? currencySign + " " : ("");
            String endStr = (isCurrency) ? ("Only") : ("");
            try
            {
                int decimalPlace = numb.IndexOf(".");

                endStr = signStr + endStr;

                if (decimalPlace > 0)
                {
                    wholeNo = numb.Substring(0, decimalPlace);
                    points = numb.Substring(decimalPlace + 1);
                    if (Convert.ToInt32(points) > 0)
                    {
                        andStr = (isCurrency) ? ("and") : ("point");// just to separate whole numbers from points/cents
                        if (!isCents)
                        {
                            endStr = (isCurrency) ? ("Cents " + endStr) : ("");

                            pointStr = translateCents(points);
                        }
                        else
                        {
                            pointStr = " " + points + "/100";

                        }
                    }
                }
                val = String.Format("{0} {1}{2}{3}", translateWholeNumber(Convert.ToInt64(wholeNo)), andStr, pointStr, endStr);
            }
            catch { ;}
            return val;
        }

		private static String translateCents(String cents)
        {
            String cts = "", digit = "", engOne = "";
            for (int i = 0; i < cents.Length; i++)
            {
                digit = cents[i].ToString();
                if (digit.Equals("0"))
                {
                    engOne = "Zero";
                }
                else
                {
                    //engOne = ones(digit);
                    engOne = onesMapping[Convert.ToInt32(digit)];
                }
                cts += " " + engOne;
            }
            return cts;
        }

		public static string translateWholeNumber(int number)
        {
            return translateWholeNumber((long)number);
        }

		public static string translateWholeNumber(long number)
        {
            if (number == 0)
            {
                return onesMapping[number];
            }

            string sign = "Positive";
            if (number < 0)
            {
                sign = "Negative";
                number = Math.Abs(number);
            }

            string retVal = null;
            int group = 0;
            while (number > 0)
            {
                int numberToProcess = (int)(number % 1000);
                number = number / 1000;

                string groupDescription = ProcessGroup(numberToProcess);
                if (groupDescription != null)
                {
                    if (group > 0)
                    {
                        retVal = groupMapping[group] + " " + retVal;
                    }
                    retVal = groupDescription + " " + retVal;
                }

                group++;
            }

            //return sign + " " + retVal;
            return retVal;
        }
		#endregion
    }
}
